/*******************************************************************************
 * StandardPlaylistManager.cpp
 *
 * Copyright (c) 2012, Varuna L Amachi. All rights reserved.
 *
 * This program/library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program/library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 ******************************************************************************/

#include "StandardPlaylistManager.h"
#include "core/utils/Utils.h"
#include "core/manager/T.h"

#include <QList>
#include <QSize>
#include <QFont>



using namespace Tanyatu;

using namespace Component;

QString StandardPlaylistManager::COMPONENT_NAME =
        "Tanyatu::Component::StandardPlaylistManager";


QString StandardPlaylistManager::COMPONENT_MODULE =
        "Tanyatu::Core";


StandardPlaylistManager::StandardPlaylistManager( QObject *parent )
    :AbstractPlaylistManager( parent ),
      m_itemList( new QList< Model::SavedPlaylist *>() )
{

}

bool StandardPlaylistManager::init()
{
    //We're doing lazy loading hence the commenting
//    bool result = true;
    bool result = DATA_RETRIEVER()->getPlaylists( m_playlists );
    QHash< QString, Model::SavedPlaylist *>::iterator it = m_playlists.begin();
    QList< QString > *contents = 0;
    for( ; it != m_playlists.end(); it ++) {
        contents = new QList< QString >();
        m_itemList->append( it.value() );
        loadPlaylist( it.key() );
    }
    return result;
}

void StandardPlaylistManager::resetItemList()
{
    m_itemList->clear();
    QHash< QString, Model::SavedPlaylist *>::iterator it = m_playlists.begin();
    for( ; it != m_playlists.end(); it ++) {
        m_itemList->append( it.value() );
    }
}

StandardPlaylistManager::~StandardPlaylistManager()
{

    clear();
}


void StandardPlaylistManager::appendToPlaylist( QString playlistName,
                                      QList< QString > &trackIds )
{
    QList< QString > *itemIds = m_playlistToTrackIds.value( playlistName );
    if( itemIds ) {
        itemIds->append( trackIds );
        emit playlistContentModified( m_playlists.value( playlistName ));
    }
}


void StandardPlaylistManager::appendToPlaylist( QString playlistName,
                                                QString trackId)
{
    QList< QString > *itemIds = m_playlistToTrackIds.value( playlistName );
    if( itemIds ) {
        itemIds->append( trackId );
        emit playlistContentModified( m_playlists.value( playlistName ));
    }
}


bool StandardPlaylistManager::deletePlaylist( QString playlistName )
{
    if( m_playlists.contains( playlistName )) {
        beginResetModel();
        Model::SavedPlaylist *playlist = m_playlists.value( playlistName );
        emit aboutToRemovePlaylist( playlist );
        m_playlists.remove( playlistName );
        m_playlistToTrackIds.remove( playlistName );
        resetItemList();
        delete playlist;
        endResetModel();
        T::get()->dataUpdater()->removePlaylist( playlistName );
        emit playlistRemoved( playlistName );
        return true;
    }
    return false;
}


bool StandardPlaylistManager::createPlaylist( QString playlistName )
{
    if( ! m_playlists.contains( playlistName )) {
        int size = m_itemList->isEmpty() ? 0 : m_itemList->size() - 1;
        beginInsertRows( QModelIndex(), size, size );
        Model::SavedPlaylist *playlist = new Model::SavedPlaylist(
                    playlistName, QDateTime::currentDateTime() );
//        T::get()->dataUpdater()->add( playlist );
        m_playlists.insert( playlistName, playlist );
        m_itemList->append( playlist );
        m_playlistToTrackIds.insert( playlistName, new QList< QString >() );
        emit playlistCreated( playlist );
        endInsertRows();
        return true;
    }
    return false;
}


bool StandardPlaylistManager::setTrackIdList( QString playlistName,
                   QList< QString > &list )
{
    bool result = false;
    if( m_playlists.contains( playlistName )) {
        QList< QString > *trackList =
                m_playlistToTrackIds.value( playlistName );
        trackList->clear();
        trackList->append( list );
        emit playlistModified( m_playlists.value( playlistName ));
        result = true;
    }
    return result;
}


bool StandardPlaylistManager::clearPlaylist( QString playlistName )
{
    if( m_playlists.contains( playlistName )) {
        T::get()->dataUpdater()->clearPlaylist( playlistName );
        m_playlistToTrackIds.value( playlistName )->clear();
        emit playlistContentModified( m_playlists.value( playlistName ));
        return true;
    }
    return false;
}


bool StandardPlaylistManager::deleteAllPlaylists()
{
    emit aboutToClear();
    beginResetModel();
    foreach( Model::SavedPlaylist *playlist, ( *m_itemList )) {
        emit aboutToRemovePlaylist( playlist );
        m_playlists.remove( playlist->name() );
        delete m_playlistToTrackIds.value( playlist->name() );
        m_playlistToTrackIds.remove( playlist->name() );
        T::get()->dataUpdater()->removePlaylist( playlist->name() );
        delete playlist;
        emit playlistRemoved( playlist->name() );
    }
    m_itemList->clear();
    emit cleared();
    endResetModel();
    return true;

}

bool StandardPlaylistManager::removeTracksFromPlaylist( QString playlistId,
                                              QList< int > &trackIndices )
{
    int numRemoved = 0;
    if( trackIndices.size() > 1 ) {
        qSort( trackIndices );
    }
    if( m_playlists.contains(( playlistId ))) {
        QList< QString > *trackList = m_playlistToTrackIds.value( playlistId );
        if( trackList ) {
            for( int i = trackIndices.size() - 1; i >= 0; -- i ){
                int index = trackIndices.at( i );
                trackList->removeAt( index );
                ++ numRemoved;
            }
        }
    }
    return trackIndices.empty() ? false : ( numRemoved == trackIndices.size() );
}


void StandardPlaylistManager::ratePlaylist( QString playlistName,
                   Model::MediaRating rating )
{
    if( m_playlists.contains( playlistName )) {
        beginResetModel();
        Model::SavedPlaylist *playlist = m_playlists.value( playlistName );
        T::get()->dataUpdater()->updateRating( playlist );
        playlist->setRating( rating );
        playlistModified( playlist );
        endResetModel();
    }
}


void StandardPlaylistManager::tagItem( QString playlistName, QString tag )
{
    if( m_playlists.contains( playlistName )) {
        Model::SavedPlaylist *playlist = m_playlists.value( playlistName );
        playlist->addTag( tag );
        T::get()->dataUpdater()->updateTags( playlist );
        emit playlistModified( playlist );
    }
}

void StandardPlaylistManager::removeItemTag( QString playlistName, QString tag )
{
    if( m_playlists.contains( playlistName )) {
        Model::SavedPlaylist *playlist = m_playlists.value( playlistName );
        playlist->removeTag( tag );
        T::get()->dataUpdater()->updateTags( playlist );
        emit playlistModified( playlist );
    }
}

bool StandardPlaylistManager::hasPlaylist(QString playlistName)
{
    return m_playlists.contains( playlistName );
}

Model::SavedPlaylist *StandardPlaylistManager::playlist( QString plName ) const
{
    return m_playlists.value( plName, 0 );
}


void StandardPlaylistManager::clear()
{
    beginResetModel();
    emit aboutToClear();
    QHash< QString, QList< QString > *>::iterator it =
            m_playlistToTrackIds.begin();
    for(; it != m_playlistToTrackIds.end(); it ++ ) {
        QList< QString > *list = it.value();
        list->clear();
        delete list;
    }
    m_playlistToTrackIds.clear();
    foreach( Model::SavedPlaylist *plist, ( *m_itemList )) {
        delete plist;
    }
    m_itemList->clear();
    m_playlists.clear();
    emit cleared();
    endResetModel();

}


void StandardPlaylistManager::onPlaylistSelected( QString playlistName )
{
    beginResetModel();
    if( m_playlists.contains( playlistName )) {
        Model::SavedPlaylist *playlist = m_playlists.value( playlistName );
        playlist->setPlayCount( playlist->playCount() + 1 );
        T::get()->dataUpdater()->updatePlayCount( playlist );
    }
    endResetModel();
}

void StandardPlaylistManager::onItemRemovalFromStorage( QString trackId )
{
    QHash< QString, QList< QString > *>::iterator mapIt =
            m_playlistToTrackIds.begin();
    for( ; mapIt != m_playlistToTrackIds.end(); ++ mapIt ) {
        QList< QString > *trackList = mapIt.value();
        if( trackList->removeAll( trackId ) != 0 ) {
            emit playlistContentModified( m_playlists.value( mapIt.key() ));
        }
    }
}



const QList< QString > StandardPlaylistManager::trackIdsIn(
        QString playlistName )
{
    if( m_playlists.contains( playlistName )) {
//        loadPlaylist( playlistName );
        return *m_playlistToTrackIds.value( playlistName );
    }
    return QList< QString >();
}


quint32 StandardPlaylistManager::numTracksIn( QString playlistName ) const
{
    if( m_playlistToTrackIds.contains( playlistName )) {
//        loadPlaylist( playlistName );
        return m_playlistToTrackIds.value( playlistName )->size();
    }
    return 0;
}


quint32 StandardPlaylistManager::allPlaylists(
        QList< Model::SavedPlaylist *>& playlists )
{
    quint32 count = 0;
    foreach( Model::SavedPlaylist *plist, ( *m_itemList )) {
        playlists.append( plist );
        ++ count;
    }
    return count;
}


QString StandardPlaylistManager::displayName() const
{
    return tr("Playlist Manager");
}


QString StandardPlaylistManager::module() const
{
    return COMPONENT_MODULE;
}


QString StandardPlaylistManager::uniqueName() const
{
    return COMPONENT_NAME;
}


int StandardPlaylistManager::rowCount( const QModelIndex &parent ) const
{
    Q_UNUSED( parent );
    return m_itemList->size();
}


int StandardPlaylistManager::columnCount( const QModelIndex &parent ) const
{
    Q_UNUSED( parent );
    return 4;
}


QVariant StandardPlaylistManager::data(
        const QModelIndex &index, int role ) const
{
    if( ! index.isValid()
        || m_itemList->isEmpty()
        || index.row() >= m_itemList->size() ) {
        return QVariant();
    }
    if ( role == Qt::TextAlignmentRole ) {
        return int ( Qt::AlignLeft | Qt::AlignVCenter );
    }
    else if ( role == Qt::DisplayRole ) {
        Model::SavedPlaylist *plist = m_itemList->at( index.row() );
        switch( index.column() ) {
        case 0: return plist->name();
        case 1: return numTracksIn( plist->name() );
        case 2: return plist->playCount();
        case 3: return plist->rating();
        }
    }
    //?? Settings???
    else if( role == Qt::SizeHintRole ) {
        return QSize( 0, 18 );
    }
    else if( role == Qt::FontRole ) {
        return QFont( "Droid Sans", 9 );
    }
    return QVariant();
}


QVariant StandardPlaylistManager::headerData( int section,
                                           Qt::Orientation orientation,
                                           int role ) const
{
    Q_UNUSED( orientation )
    if ( role == Qt::TextAlignmentRole ) {
        return int( Qt::AlignLeft | Qt::AlignVCenter );
    }
    else if ( role == Qt::DisplayRole ) {
        switch( section ) {
        case 0: return tr( "Name" );
        case 1: return tr( "Tracks" );
        case 2: return tr( "Played" );
        case 3: return tr( "Rating" );
        }
    }
    return QVariant();
}


QModelIndex StandardPlaylistManager::index( int row, int column,
                                         const QModelIndex &parent ) const
{
    Q_UNUSED( parent )
    return createIndex(row, column);
}


QModelIndex StandardPlaylistManager::parent( const QModelIndex &child ) const
{
    Q_UNUSED( child )
    return QModelIndex();
}


bool StandardPlaylistManager::hasChildren( const QModelIndex &parent ) const
{
    if(! parent.isValid()) {
        return true;
    }
    return false;
}


Qt::ItemFlags StandardPlaylistManager::flags( const QModelIndex &index ) const
{
    Qt::ItemFlags flags = QAbstractItemModel::flags( index );
    if( index.column() == 3 ) {
        return flags |= Qt::ItemIsEditable;
    }
    return flags;
}


bool StandardPlaylistManager::setData( const QModelIndex &index,
                                    const QVariant &value,
                                    int role )
{
    Q_UNUSED( role );
    if( index.column() == 3 ) {
        Model::SavedPlaylist *plist = m_itemList->at( index.row() );
        ratePlaylist( plist->name() , Utils::getRatingFromInt( value.toInt() ));
        return true;
    }
    return false;
}

void StandardPlaylistManager::loadPlaylist( const QString playlistName )
{
    if( ! m_playlistToTrackIds.contains( playlistName ) ) {
        QList< QString > *list = new QList< QString >();
        if( T::get()->dataRetriever()->getPlaylistContent( playlistName,
                                                           *list )) {
            m_playlistToTrackIds.insert( playlistName, list );
        }
    }
}






